package com.sddz.pacs.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.Producer;
import com.sddz.pacs.annotation.SysLogger;
import com.sddz.pacs.dto.JsonResult;
import com.sddz.pacs.dto.LoginVo;
import com.sddz.pacs.entity.SysRole;
import com.sddz.pacs.entity.SysUser;
import com.sddz.pacs.exception.CustomerException;
import com.sddz.pacs.service.SysRolePermissionService;
import com.sddz.pacs.service.SysRoleService;
import com.sddz.pacs.service.SysUserService;
import com.sddz.pacs.support.Constant;
import com.sddz.pacs.support.ResultConstant;
import com.sddz.pacs.util.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;

@Controller
@Api(description = "登陆相关接口")
public class LoginController {

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private Producer captchaProducer;

    @Autowired
    private SysRoleService sysRoleService;
    @Autowired
    private SysRolePermissionService sysRolePermissionService;

    @Autowired
    private SysUserService sysUserService;

    @ApiOperation(value="获取验证码", notes="获取登录所需验证码")
    @RequestMapping(value = "/common/captcha",method = RequestMethod.GET)
    public void captcha(HttpServletRequest request , HttpServletResponse response)throws ServletException, IOException {
        // 设置过期时间
        response.setDateHeader("Expires", 0);
        // 设置不缓存
        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
        // 设置IE扩展不缓存
        response.addHeader("Cache-Control", "post-check=0, pre-check=0");
        // 设置HTTP1.0标准请求头
        response.setHeader("Pragma", "no-cache");

        // 返回类型
        response.setContentType("image/jpeg");

        // 验证码文字
        String capText = captchaProducer.createText();

        // 放入session中，以便校验
        request.getSession().setAttribute(Constants.KAPTCHA_SESSION_KEY, capText);

        // 创建返回图片
        BufferedImage bi = captchaProducer.createImage(capText);

        ServletOutputStream out = response.getOutputStream();

        // write the data out
        ImageIO.write(bi, "jpg", out);
        try {
            out.flush();
        } finally {
            out.close();
        }
    }

    @PostMapping(value = "login")
    @ResponseBody
    @SysLogger(value = "管理员登录",type = "管理员登录日志管理")
    @ApiOperation(value="登录", notes="用户登录系统")
    @ApiImplicitParam(name = "user",value = "用户json对象",required = true)
    public JsonResult login(@RequestBody LoginVo loginVo) throws Exception {
        try{
            String cap = ShiroUtils.getKaptcha(Constants.KAPTCHA_SESSION_KEY);
            if(!cap.equalsIgnoreCase(loginVo.getCaptcha())){
                return JsonResult.failure("验证码输入有误，请重新输入！");
            }


            //2.生成用户token，Shiro框架校验用户是否合法
            Subject subject = ShiroUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken(loginVo.getUserName(), loginVo.getPassword());

            /*//获取有效期限时间
            SysUser sysUser = sysUserService.queryUserByLoginName(loginVo.getUserName());
            System.out.println("sessionId===================================="+ShiroUtils.getSession().getId());
            //登录验证通过，检验有效期限
            Long  endTimeMill =  sysUser.getEndDate().getTime();
            Long  dayMill =(long) Constant.NUM * 24 * 60 * 60 * 1000;
            //获取当前系统时间毫秒值
            long curMill = new Date().getTime();

            if((endTimeMill+dayMill)<=curMill){
                return JsonResult.failure(-1,"密码有限期限已到");
            }*/
            subject.login(token);
            ShiroUtils.getAuthenticationInfo(loginVo.getUserName());

        }catch (UnknownAccountException e) {
            return JsonResult.failure(e.getMessage());
        }catch (IncorrectCredentialsException e) {
            return JsonResult.failure("账号或密码不正确");
        }catch (LockedAccountException e) {
            return JsonResult.failure("账号已被锁定,请联系管理员");
        }catch (AuthenticationException e) {
            return JsonResult.failure("账户验证失败,请确保账户未重复登陆");
        }
        //3.用户合法校验通过，查询用户所拥有的角色和权限
        SysUser sysUser = ShiroUtils.getUserEntity();
        Set<String> permissions = new HashSet<>();
        List<SysRole> sysRoles = sysRoleService.getRolesByUserId(sysUser.getId());
        for (SysRole sysRole : sysRoles){
            //4.查询该角色所拥有的权限标识
            Set<String> permission = sysRolePermissionService.getPermissionsByRoleId(sysRole.getId());
            permissions.addAll(permission);
        }
        sysUser.setRoleList(sysRoles);
        sysUser.setPermissions(permissions);

        return JsonResult.success(sysUser,ResultConstant.LOGIN_SUCCESS);
    }


    @GetMapping("logout")
    @ResponseBody
    @ApiOperation(value="退出系统", notes="用户退出系统")
    public JsonResult logout() {
        ShiroUtils.logout();
        return JsonResult.success("退出！");
    }

    @GetMapping("unauth")
    @ResponseBody
    public JsonResult unAuth(){
        return JsonResult.failure(101,"登录超时，请重新登录");

    }

    //发送手机验证码
    @PostMapping("/sendMsg")
    @ResponseBody
    public JsonResult sendMsg(@RequestBody JSONObject params) throws UnsupportedEncodingException {
        boolean flag = false;
        String loginName =params.getString("loginName");
        String phone = params.getString("phone");
        Integer validity =  3;//三分钟内有效

        //1.校验手机号与输入的手机号是否匹配
        EntityWrapper<SysUser> ew = new EntityWrapper<>();
        ew.eq("LOGIN_NAME", loginName);
        SysUser sysUser = sysUserService.selectOne(ew);
        String userTel = "";
        if (sysUser==null||!phone.equals(sysUser.getPhone())){
            return JsonResult.failure("用户名或手机号码不正确，请重新输入。");
        }

        //2.发送短信验证码
        String code = RandomStringUtils.randomNumeric(6);
        Map<String,Object> paramMap = new HashMap<>();
        paramMap.put("mobile",phone); //接收短信的手机号码
        paramMap.put("tpl_id", Constant.COMMON_USE_MESSAGE_TEMPLATE_ID);//短信模板ID，请参考个人中心短信模板设置
        paramMap.put("tpl_value","#code#=" + code+"&#m#="+validity);

        JSONObject retJson = MessageUtil.sendMessage(paramMap);
        if(retJson.getIntValue("error_code") == 0){
            //如果发送成功，缓存短信验证码key值为当前手机号
            flag = true;
            try {
                redisUtil.setObject(phone + "_vcode",code,validity * 60  );
            } catch (Exception e) {
                throw new CustomerException("缓存验证码失败");
            }
        }
        return flag ? JsonResult.success(code,"短信已下发至您的手机，请注意查收！") : JsonResult.failure("发送失败，请稍后重试！");
    }

    //校验短信验证码
    @PostMapping("/verifyCode")
    @ResponseBody
    public JsonResult verifyCode(@RequestBody JSONObject params) throws UnsupportedEncodingException {
        String phone = params.getString("phone");
        String msgCode = SerializeUtil.serialize(params.getString("code"));
        try{
            //1.校验验证码
            String cacheCode = redisUtil.getString(phone + "_vcode");
            if(org.apache.commons.lang3.StringUtils.isEmpty(cacheCode))
                return  JsonResult.failure("验证码失效，请重新发送！");
            if (!msgCode.equalsIgnoreCase(cacheCode)){
                return JsonResult.failure("短信验证码输入有误，请重新输入！");
            }else{
                //2.输入成功，手工清除该验证码缓存
                redisUtil.del(phone + "_vcode");
            }
        }catch (Exception ex){
            throw new CustomerException("操作缓存失败！");
        }
        return  JsonResult.success("验证成功");
    }

    @PostMapping("/changePass")
    @ResponseBody
    public JsonResult updatePass(@RequestBody JSONObject params){
        boolean flag = false;
        String loginName =params.getString("loginName");
        String password = params.getString("password");
        String newPassword=params.getString("newPassword");

        //1.根据用户名查找密码
        EntityWrapper<SysUser> ew = new EntityWrapper<>();
        ew.eq("LOGIN_NAME", loginName);
        SysUser sysUser = sysUserService.selectOne(ew);

        //3.校验旧密码是否输入正确
        String salt = sysUser.getSalt();
        password = ShiroUtils.encodeSalt(password,sysUser.getSalt());
        if(!password.equalsIgnoreCase(sysUser.getPassword())){
            return JsonResult.failure("密码输入有误，请重新输入！");
        }
        //2.校验通过，更新密码
        newPassword = ShiroUtils.encodeSalt(newPassword,sysUser.getSalt());
        sysUser.setPassword(newPassword);
        flag = sysUserService.updateById(sysUser);
        return flag ? JsonResult.success("修改成功") : JsonResult.failure("修改失败，请稍后重试！");
    }
}
